#include "syntax_parser.h"
#include "errors_warnings.h"

#include "main_container.h"
extern MainContainer * CompilerData;


void Parser::Parse_GppFile(SyntaxTreeNode * parent) {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("Parse_GppFile");
#endif

	LexicUnit currentUnit;

#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif

	// get current lexic unit
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	
	// if current lexic unit is in the select set of {simulation, namespace, enum, class, model, numeric, trace
	//												template, public, private, start, process, int, float,
	//												bool, state, time, void, Facility, Storage, Queue, ADTable,
	//												Group, OutputStream, NAME, abstract, protected,
	//												virtual, override, static, final, const, endOfFile
	if(( currentUnit.type == LUTypeKeyword && 
		(currentUnit.subtype == KeywordUsing || currentUnit.subtype == KeywordSimulation || currentUnit.subtype == KeywordTrace
		|| currentUnit.subtype == KeywordNamespace || currentUnit.subtype == KeywordEnum
		|| currentUnit.subtype == KeywordClass || currentUnit.subtype == KeywordModel
		|| currentUnit.subtype == KeywordNumeric || currentUnit.subtype == KeywordTemplate
		|| currentUnit.subtype == KeywordPublic || currentUnit.subtype == KeywordPrivate
		|| currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess
		|| currentUnit.subtype == KeywordInt || currentUnit.subtype == KeywordFloat
		|| currentUnit.subtype == KeywordBool || currentUnit.subtype == KeywordState
		|| currentUnit.subtype == KeywordTime || currentUnit.subtype == KeywordVoid
		|| currentUnit.subtype == KeywordFacility || currentUnit.subtype == KeywordStorage
		|| currentUnit.subtype == KeywordQueue || currentUnit.subtype == KeywordADTable
		|| currentUnit.subtype == KeywordGroup || currentUnit.subtype == KeywordOutputStream
		|| currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordStatic
		|| currentUnit.subtype == KeywordFinal || currentUnit.subtype == KeywordConst
		|| currentUnit.subtype == KeywordAbstract || currentUnit.subtype == KeywordProtected
		|| currentUnit.subtype == KeywordOverride))
		|| currentUnit.type == LUTypeIdentifier || (currentUnit.type == LUTypeSpecialType && 
		currentUnit.subtype == endOfFile))	
	{
		// write type of production in this node
		parent->Production = Gr_GppFile__UsingDirectives_FileBody_endOfFile;

		// process nonterminal symbol <using_directives> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_UsingDirectives(newNode0);

		// process nonterminal symbol <file_body> 
		SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode1);
		Parse_FileBody(newNode1);

		// process terminal symbol 'endOfFile' 
		currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	// if current lexic unit is in the select set of {endOfFile}
		if( currentUnit.type == LUTypeSpecialType && currentUnit.subtype == endOfFile)
		{
			SyntaxTreeNode * newNode2 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode2);
			newNode2->LexUnitID=this->CurrentLexicPosition;
			newNode2->Production=Gr_Terminal;
			//increase counter
			CurrentLexicPosition++;
		}
		else
		{
			//report syntactic error
			CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_END_OF_FILE_MATCH);
			//increase counter
			CurrentLexicPosition++;
		}

	}

	else
	{
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_GPP_FILE_BEGINING);
		// This is recovoring from error
        this->CurrentLexicPosition++;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_GppFile");
#endif
}


// <using_directives> ~ <using_directive> <using_directives>  {using}
// <using_directives> ~ ? {trace, simulation, namespace, enum, class, model, numeric, template, public, private, start, process, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, abstract, protected, virtual, override, static, final, const, endOfFile, }, define, generate, terminate, advance, enter, leave, seize, release, inqueue, outqueue, arrive, depart, goto, if, wait, join, create, split, gather, execute, exec}
void Parser::Parse_UsingDirectives(SyntaxTreeNode * parent) {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("Parse_UsingDirectives");
#endif

	LexicUnit currentUnit;
	// get current lexic unit

	do	{

#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif

	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		
	// if current lexic unit is in the select set of { using }
	if (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordUsing)	{
		// write type of production in this node
		parent->Production = Gr_UsingDirectives__UsingDirective_UsingDirectives;

		// process nonterminal symbol <using_directive> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_UsingDirective(newNode0);

	}


		// if current lexic unit is in the select set of {simulation, namespace, enum, class, model, numeric, 
		//												template, public, private, start, process, int, float,
		//												bool, state, time, void, Facility, Storage, Queue, ADTable,
		//												Group, OutputStream, NAME, abstract, protected,
		//												virtual, override, static, final, const, endOfFile, }, define,
		//												generate, terminate, advance, enter, leave, seize, release,
		//												inqueue, outqueue, arrive, depart, goto, if, wait, join, create,
		//												split, gather, execute, exec}
	else if (
		( currentUnit.type == LUTypeKeyword && 
		( currentUnit.subtype == KeywordSimulation || currentUnit.subtype == KeywordNamespace
		|| currentUnit.subtype == KeywordEnum || currentUnit.subtype == KeywordTrace
		|| currentUnit.subtype == KeywordClass || currentUnit.subtype == KeywordModel
		|| currentUnit.subtype == KeywordNumeric || currentUnit.subtype == KeywordTemplate
		|| currentUnit.subtype == KeywordPublic || currentUnit.subtype == KeywordPrivate
		|| currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess
		|| currentUnit.subtype == KeywordInt || currentUnit.subtype == KeywordFloat
		|| currentUnit.subtype == KeywordBool || currentUnit.subtype == KeywordState
		|| currentUnit.subtype == KeywordTime || currentUnit.subtype == KeywordVoid
		|| currentUnit.subtype == KeywordFacility || currentUnit.subtype == KeywordStorage
		|| currentUnit.subtype == KeywordQueue || currentUnit.subtype == KeywordADTable
		|| currentUnit.subtype == KeywordGroup || currentUnit.subtype == KeywordOutputStream
		|| currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordStatic
		|| currentUnit.subtype == KeywordFinal || currentUnit.subtype == KeywordConst
		|| currentUnit.subtype == KeywordAbstract || currentUnit.subtype == KeywordProtected
		 
		|| currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordDefine
		|| currentUnit.subtype == KeywordGenerate || currentUnit.subtype == KeywordTerminate
		|| currentUnit.subtype == KeywordAdvance || currentUnit.subtype == KeywordEnter
		|| currentUnit.subtype == KeywordLeave || currentUnit.subtype == KeywordSeize
		|| currentUnit.subtype == KeywordRelease || currentUnit.subtype == KeywordInqueue
		|| currentUnit.subtype == KeywordOutqueue || currentUnit.subtype == KeywordArrive
		|| currentUnit.subtype == KeywordDepart || currentUnit.subtype == KeywordGoto
		|| currentUnit.subtype == KeywordIf || currentUnit.subtype == KeywordWait
		|| currentUnit.subtype == KeywordJoin || currentUnit.subtype == KeywordCreate
		|| currentUnit.subtype == KeywordSplit || currentUnit.subtype == KeywordGather
		|| currentUnit.subtype == KeywordExecute || currentUnit.subtype == KeywordExec))
		|| currentUnit.type == LUTypeIdentifier 
		|| (currentUnit.type == LUTypeSpecialType && currentUnit.subtype == endOfFile)
		|| (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterRightCurlyBrace)
		)		
	{
		// write type of production in this node
  // ToDo-Nikola: Da nije mozda Gr_UsingDirectives__epsilon?
		parent->Production = Gr_UsingDirectives__UsingDirective_UsingDirectives;
		break;
	}
	else
	{
	// ERROR has been found
	// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_USING_DIRECTIVES_BEGINING);
	// MAKE LOGICAL RECOVERING
		this->CurrentLexicPosition++;
		 break;
	}

	}while(1);
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_UsingDirectives");
#endif
}



// <using_directive> ~ using <name> ;  {using}
// <using_directive> ~ using <name> as NAME ;  {using}
void Parser::Parse_UsingDirective(SyntaxTreeNode * parent)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("Parse_UsingDirective");
#endif
	LexicUnit currentUnit;

	// get current lexic unit
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	
	// if current lexic unit is in the select set of {using } 

	if(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordUsing)
	{
		
		// process terminal symbol 'using' 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		newNode0->LexUnitID=this->CurrentLexicPosition;
		newNode0->Production=Gr_Terminal;
		//increase counter
		CurrentLexicPosition++;

		// process nonterminal symbol <name> 
		SyntaxTreeNode * newNode1 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode1);
		Parse_Name(newNode1);

	   currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
		if(currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterSemicolon)
		{
			// write type of production in this node
			parent->Production =Gr_UsingDirective__using_Name_spSemiCol;

			// process terminal symbol ';' 
			SyntaxTreeNode * newNode2 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode2);
			newNode2->LexUnitID=this->CurrentLexicPosition;
			newNode2->Production=Gr_Terminal;
			//increase counter
			CurrentLexicPosition++;
		}
		else if(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordAs)
		{
         // write type of production in this node
			parent->Production =Gr_UsingDirective__using_Name_as_NAME_spSemiCol;

			// process terminal symbol 'as' 
			SyntaxTreeNode * newNode2 = new SyntaxTreeNode();
			parent->Nodes->Add(newNode2);
			newNode2->LexUnitID=this->CurrentLexicPosition;
			newNode2->Production=Gr_Terminal;
			//increase counter
			CurrentLexicPosition++;

			// process terminal symbol 'NAME' 
			currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
			// if current lexic unit is in the select set of { NAME	}
			if( currentUnit.type == LUTypeIdentifier )
			{
				SyntaxTreeNode * newNode3 = new SyntaxTreeNode();
				parent->Nodes->Add(newNode3);
				newNode3->LexUnitID=this->CurrentLexicPosition;
				newNode3->Production=Gr_Terminal;
				//increase counter
				CurrentLexicPosition++;
			}
			else
			{
				//report syntactic error
				CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_NAME_MATCH);
				//increase counter
				CurrentLexicPosition++;
			}

			// process terminal symbol ';' 
			currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
			// if current lexic unit is in the select set of { ; }
			if( currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterSemicolon)
			{
				SyntaxTreeNode * newNode4 = new SyntaxTreeNode();
				parent->Nodes->Add(newNode4);
				newNode4->LexUnitID=this->CurrentLexicPosition;
				newNode4->Production=Gr_Terminal;
				//increase counter
				CurrentLexicPosition++;
			}
			else
			{
				//report syntactic error
				CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_SEMICOLON_MATCH);
				//increase counter
				CurrentLexicPosition++;
			}


		}
		else
		{
			//report syntactic error
			CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_AS_MATCH);
			//increase counter
			CurrentLexicPosition++;
		}
		
	}
	else
	{
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_USING_DIRECTIVE_BEGINING);
		// This is recovoring from error
        this->CurrentLexicPosition++;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_UsingDirective");
#endif
}


	// <file_body> ~ <main_definition> <file_body>  {namespace, enum, class, model, numeric, template, public, trace
	//												private, start, process, int, float, bool, state, time, void,
	//												Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, abstract,
	//												protected, virtual, override, static, final, const}
	// <file_body> ~ <simulation> <file_body>  {simulation}
	// <file_body> ~ ? {endOfFile, }}
void Parser::Parse_FileBody(SyntaxTreeNode * parent) {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("Parse_FileBody");
#endif

	LexicUnit currentUnit;
	
 do	{

#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif

  // get current lexic unit
	 currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	// if current lexic unit is in the select set of 
	//		{namespace, enum, class, model, numeric, template, public, private, start,
	//		process, int, float, bool, state, time, void, Facility, Storage, Queue, 
	//		ADTable, Group, OutputStream, NAME, abstract, protected, 
	//		virtual, override, static, final, const } 

 	if( currentUnit.type == LUTypeKeyword && 
   		(currentUnit.subtype == KeywordNamespace || currentUnit.subtype == KeywordEnum|| currentUnit.subtype == KeywordTrace
 		|| currentUnit.subtype == KeywordClass || currentUnit.subtype == KeywordModel
 		|| currentUnit.subtype == KeywordNumeric || currentUnit.subtype == KeywordTemplate
 		|| currentUnit.subtype == KeywordPublic || currentUnit.subtype == KeywordPrivate
 		|| currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess
 		|| currentUnit.subtype == KeywordInt || currentUnit.subtype == KeywordFloat
 		|| currentUnit.subtype == KeywordBool || currentUnit.subtype == KeywordState
 		|| currentUnit.subtype == KeywordTime || currentUnit.subtype == KeywordVoid
 		|| currentUnit.subtype == KeywordFacility || currentUnit.subtype == KeywordStorage
 		|| currentUnit.subtype == KeywordQueue || currentUnit.subtype == KeywordADTable
 		|| currentUnit.subtype == KeywordGroup || currentUnit.subtype == KeywordOutputStream
 		|| currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordStatic
 		|| currentUnit.subtype == KeywordFinal || currentUnit.subtype == KeywordConst
 		|| currentUnit.subtype == KeywordAbstract || currentUnit.subtype == KeywordProtected
 		|| currentUnit.subtype == KeywordOverride) || (currentUnit.type == LUTypeIdentifier))	{
		 // write type of production in this node
		 parent->Production =Gr_FileBody__MainDefinition_FileBody;

		// process nonterminal symbol <main_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_MainDefinition(newNode0);


	}
		// if current lexic unit is in the select set of {simulation  } 
	else if( currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordSimulation)
		{
		// write type of production in this node
		parent->Production =Gr_FileBody__Simulation_FileBody;

		// process nonterminal symbol <simulation> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_Simulation(newNode0);

	}
		// if current lexic unit is in the select set of {endOfFile, } } 
	else if((currentUnit.type == LUTypeSpecialType && currentUnit.subtype == endOfFile)
			|| (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterRightCurlyBrace))

	{
		// write type of production in this node
		parent->Production =Gr_FileBody__MainDefinition_FileBody;
		break;

	}

	else
	{
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_FILE_BODY_BEGINING);
		// This is recovoring from error
        this->CurrentLexicPosition++;
		break;
	}
	}while(1);
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_FileBody");
#endif

}

//void Parser::Parse_MainDefinition(SyntaxTreeNode * parent)
//{
//}

